package com.yzg.simple.nio.chat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * @author misterWei
 * @mailbox mynameisweiyan@gmail.com
 *
 * 基于NIO 做出群聊系统
 */
public class ChatServer {

    private Selector selector;
    private ServerSocketChannel serverSocketCannel;
    private static final Integer PORT = 6868;

    // 默认初始化信息
    public ChatServer()  {
        try {
            selector = Selector.open();
            serverSocketCannel = ServerSocketChannel.open();
            //绑定端口
            serverSocketCannel.bind(new InetSocketAddress(PORT));
            //设置非阻塞
            serverSocketCannel.configureBlocking(false);
            //注册到选择器(selector)
            serverSocketCannel.register(selector, SelectionKey.OP_ACCEPT);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    //接受消息 提示上线以及下线信息
    public void initServerConnection(){
        SocketChannel socketChannel2 = null;
        SelectionKey selectionKey2 = null;
        try {
            while (true){
                int i = selector.select(2000);
                if (i > 0){
                    Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
                    while (selectionKeyIterator.hasNext()){
                        SelectionKey selectionKey = selectionKeyIterator.next();
                        if (selectionKey.isAcceptable()){
                            //客户端第一次连接 全局提示 除了自己
                           SocketChannel socketChannel = serverSocketCannel.accept();
                           // 设置非阻塞
                           socketChannel.configureBlocking(false);
                            //发送消息
                            socketChannel.register(selector,SelectionKey.OP_READ);
                            sendMesInfoToClients(socketChannel.getRemoteAddress()+" 上线了",socketChannel);
                        }

                        if (selectionKey.isReadable()){
                            //读取数据并转发到客户端
                           SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                            socketChannel2 =socketChannel;
                            selectionKey2= selectionKey;
                            ByteBuffer mesBuffer = ByteBuffer.allocate(1024);
                            socketChannel.read(mesBuffer);
                            sendMesInfoToClients(socketChannel.getRemoteAddress()+":"+ new String(mesBuffer.array()),socketChannel);
                        }


                        //删除当前 避免重复
                        selectionKeyIterator.remove();
                    }
                }

            }

        }catch (IOException e){
            //如果是异常就说明有人下线
            //删除该连接 关闭该通道
            if (socketChannel2 != null && selectionKey2 != null){
                String rmoPath = null;
                try {
                    rmoPath = socketChannel2.getRemoteAddress().toString().substring(1);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                selectionKey2.cancel();
                try {
                    socketChannel2.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                //通知所有
                try {
                   // sendMesInfoToClients(rmoPath+"下线了",null);
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }else {
                e.printStackTrace();
            }


        }finally {

        }

    }

    private void sendMesInfoToClients(String mes, SocketChannel socketChannel) throws IOException {
        try {
            // 注意  keys() 是获取所有连接的 而selectedKeys() 是只获取当前活跃的
            Iterator<SelectionKey> selectionKeyIterator = selector.keys().iterator();
            while (selectionKeyIterator.hasNext()){
                SelectionKey nextKey = selectionKeyIterator.next();
                Channel targetChannel = nextKey.channel();
                if (targetChannel instanceof SocketChannel && socketChannel != targetChannel){
                    //发送
                    if (targetChannel.isOpen())
                    ((SocketChannel) targetChannel).write(ByteBuffer.wrap(mes.getBytes()));
                }

            }

        }catch (IOException e){
           e.printStackTrace();
        }finally {

        }

    }


    public static void main(String[] args) {
        ChatServer chatServer = new ChatServer();
        chatServer.initServerConnection();

    }
}
